/*************************************************************************** 
 * (c) 2006 Dmitry Osinovsky, osdmsoftware@gmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License as        *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 ***************************************************************************/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using Microsoft.Win32;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.InteropServices;
using OsdmSoftware.CommonLibrary;
using System.IO;

namespace OsdmSoftware.PocketPicture
{
    public partial class PocketPictureForm: Form
    {
        public const string RegKey = "HKEY_CURRENT_USER\\Software\\PocketPicture";

        List<Bitmap> undoStack = new List<Bitmap>();
        List<Bitmap> redoStack = new List<Bitmap>();
        Bitmap lastModifications;

        string fileName;
        PaintTool mode;
        int penWidth;
        Action selectedPen;
        bool Initing = true;
        Dictionary<string, ToolMenu> menus = new Dictionary<string, ToolMenu>();
        //Dictionary<Action, Action> defaultMenuItems = new Dictionary<Action, Action>();
        bool hasUnsavedModifications = false;
        PaintTool defaultMode = null;
        int undoStackDepth = 5;
        ToolDockDirection toolPanelDockDirection = ToolDockDirection.Left;
        ToolDockDirection paletteDockDirection = ToolDockDirection.Left;
        PaletteColorNumber paletteColorNumber = PaletteColorNumber.Colors125;
        bool fullScreenMode = false;
        bool hideTitleBar = true;
        bool paletteControlDropDown = true;
        bool reducedMode;
        bool educationalMode = true;
        Action activeMainMenuItem;
        Color selectedColor = Color.White;
        bool paletteAsHSV = false;

        ToolPanelElement lastElement = null;

        int lastWidth = 0;

        ViewPaletteAction viewPaletteAction;
        //ToolCollection penWidthTC;
        SelectionTool selectionTool;
        ColorDialogAction colorDialogAction;
        TransparentSelectionAction transparentSelectionAction;

        bool hideHintLabel = false;

        FloatingForm floatingForm = null;

        int airBrushDensity = 20;
        int semitransparentBrushTransparency = 60;
        int tolerance = 0;
        bool reorderTabsAfterSelection = true;
#if PocketPC
        bool useStandartFileDialog = false;
#endif
        bool returnToPreviousModeAfterColorSelectionTool = true;
        bool currentColorIsTransparentColorForSelection = true;
        bool showRedo = true;

        public int PenWidth { get { return penWidth; } set { penWidth = value; } }
        public PaintTool Mode { get { return mode; } set { SetMode(value); } }
        public Dictionary<string, ToolMenu> Menus { get { return menus; } }
        //public Dictionary<Action, Action> DefaultMenuItems { get { return defaultMenuItems; } }
        public Action SelectedPen { get { return selectedPen; } set { selectedPen = value; } }
        public Bitmap LastModifications { get { return lastModifications; } }
        public SelectionTool SelectionTool { get { return selectionTool; } }
        public Action ActiveMainMenuItem { get { return activeMainMenuItem; } }
        public ColorDialogAction ColorDialogAction { get { return colorDialogAction; } }
        public PaintTool DefaultMode { get { return defaultMode; } }

        [EditThisProperty, SerializeThisProperty, Label("Dock toolbar to")]
        public ToolDockDirection ToolPanelDockDirection { get { return toolPanelDockDirection; } set { toolPanelDockDirection = value; } }

        //[EditThisProperty, SerializeThisProperty, Label("Dock palette to")]
        public ToolDockDirection PaletteDockDirection { get { return paletteDockDirection; } set { paletteDockDirection = value; } }

        [EditThisProperty, SerializeThisProperty, Label("Undo buffer size")]
        public int UndoStackDepth { get { return undoStackDepth; } set { undoStackDepth = value; } }

        //[EditThisProperty, SerializeThisProperty, Label("Number of colors in palette")]
        public PaletteColorNumber PaletteColorNumber { get { return paletteColorNumber; } set { paletteColorNumber = value; } }

        [EditThisProperty, SerializeThisProperty, Label("Reduced mode")]
        public bool ReducedMode { get { return reducedMode; } set { reducedMode = value; } }

        //[SerializeThisProperty, Label("Floating tool panel")]
        public bool FullScreenMode { get { return fullScreenMode; } set { fullScreenMode = value; } }

        [EditThisProperty, SerializeThisProperty, Label("Hide title bar")]
        public bool HideTitleBar { get { return hideTitleBar; } set { hideTitleBar = value; } }

        //[EditThisProperty, SerializeThisProperty, Label("Drop down palette")]
        public bool PaletteControlDropDown { get { return paletteControlDropDown; } set { paletteControlDropDown = value; } }

        [EditThisProperty, SerializeThisProperty, Label("Hide hint bar")]
        public bool HideHintLabel { get { return hideHintLabel; } set { hideHintLabel = value; } }

        [EditThisProperty, SerializeThisProperty, Label("Hint mode")]
        public bool EducationalMode { get { return educationalMode; } set { educationalMode = value; } }

        [EditThisProperty, SerializeThisProperty, Label("HSV instead of palette\r\n(experimental)")]
        public bool PaletteAsHSV { get { return paletteAsHSV; } set { paletteAsHSV = value; } }

        [EditThisProperty, SerializeThisProperty, Label("Air brush density\r\n(0-100)")]
        public int AirBrushDensity { get { return airBrushDensity; } set { airBrushDensity = value; } }

        [EditThisProperty, SerializeThisProperty, Label("Semitransparent\r\nbrush\r\ntransparency\r\n(0-100)")]
        public int SemitransparentBrushTransparency { get { return semitransparentBrushTransparency; } set { semitransparentBrushTransparency = value; } }

        [EditThisProperty, SerializeThisProperty, Label("Floodfill\r\ntolerance\r\n(0-128)")]
        public int Tolerance { get { return tolerance; } set { tolerance = value; } }

        [EditThisProperty, SerializeThisProperty, Label("Reorder tabs on clicks")]
        public bool ReorderTabsAfterSelection { get { return reorderTabsAfterSelection; } set { reorderTabsAfterSelection = value; } }

#if PocketPC
        [EditThisProperty, SerializeThisProperty, Label("Use standart Windows file dialog")]
        public bool UseStandartFileDialog { get { return useStandartFileDialog; } set { useStandartFileDialog = value; } }
#endif

        [EditThisProperty, SerializeThisProperty, Label("Select previous tool after\r\nusing color selection tool")]
        public bool ReturnToPreviousModeAfterColorSelectionTool { get { return returnToPreviousModeAfterColorSelectionTool; } set { returnToPreviousModeAfterColorSelectionTool = value; } }

        [EditThisProperty, SerializeThisProperty, Label("When selecting area make\r\npixels with current color transparent")]
        public bool CurrentColorIsTransparentColorForSelection { get { return currentColorIsTransparentColorForSelection; } set { currentColorIsTransparentColorForSelection = value; } }

        [EditThisProperty, SerializeThisProperty, Label("Show redo button")]
        public bool ShowRedo { get { return showRedo; } set { showRedo = value; } }

        public Color PaletteSelectedColor
        {
            get
            {
                return selectedColor; //PaletteControl.SelectedColor;
            }
            set
            {
                if (selectedColor == value && PaletteControl.SelectedColor == value)
                    return;
                selectedColor = value;
                if (!Initing)
                    Registry.SetValue(RegKey, "SelectedColor", PaletteSelectedColor.ToArgb());
                mode.ClearStatus();
                smallPaletteControl1.ColorChanged(PaletteSelectedColor);
                PaletteControl.SelectedColor = value;
            }
        }

        public ToolMenu MainMenu;
        public ToolMenu Undo;
        public ToolMenu Contours;
        public ToolMenu BrushType;
        public ToolMenu Figures;
        public ToolMenu Selection1;
        public ToolMenu Selection2;
        public ToolMenu Selection3;
        public ToolMenu File1;
        public ToolMenu File2;
        public ToolMenu Zoom1;
        public ToolMenu Zoom2;
        public ToolMenu BrushSize;
        public ToolMenu AdvancedColor;

        public PocketPictureForm()
        {
            InitializeComponent();
#if SmallIcons
            ImageList.Images.Add(OsdmSoftware.PocketPicture.Properties.Resources.FloatMenuAction16);
#else
            ImageList.Images.Add(OsdmSoftware.PocketPicture.Properties.Resources.FloatMenuAction);
#endif
            HintLabel.Text = "";

            Registry.SetValue(RegKey, "Started", "Yes");
            penWidth = Convert.ToInt32(Registry.GetValue(RegKey, "PenWidth", 1));
            BitmapZoomer.ZoomFactor = BitmapZoomer.ZoomFactorUnit; //Convert.ToInt32(Registry.GetValue(RegKey, "ZoomFactor", 1));
            //BitmapZoomer.debugLabel = HintLabel;
            /*MainMenu = new ToolMenu("MainToolBar", MainToolBar);
            Contours = new ToolMenu("Contours", toolPanel1);
            BrushType = new ToolMenu("BrushType", toolPanel2);
            Figures = new ToolMenu("FilledFigures", toolPanel1);
            Selection1 = new ToolMenu("Selection1", toolPanel1);
            Selection2 = new ToolMenu("Selection2", toolPanel2);
            Selection3 = new ToolMenu("Selection3", toolPanel3);
            File1 = new ToolMenu("File1", toolPanel1);
            File2 = new ToolMenu("File2", toolPanel2);
            Zoom1 = new ToolMenu("Zoom1", toolPanel1);
            Zoom2 = new ToolMenu("Zoom2", toolPanel2);
            BrushSize = new ToolMenu("BrushSize", toolPanel3);
            AdvancedColor = new ToolMenu("AdvancedColor", toolPanel4);*/
            MainMenu = new ToolMenu("MainToolBar", MainToolBar);
            Contours = new ToolMenu("Contours", toolPanel1);
            BrushType = new ToolMenu("BrushType", toolPanel1);
            //Figures = new ToolMenu("FilledFigures", toolPanel2);
            Selection1 = new ToolMenu("Selection1", toolPanel1);
            Selection2 = new ToolMenu("Selection2", toolPanel2);
            //Selection3 = new ToolMenu("Selection3", toolPanel3);
            File1 = new ToolMenu("File1", toolPanel1);
            File2 = new ToolMenu("File2", toolPanel2);
            Zoom1 = new ToolMenu("Zoom1", toolPanel1);
            Zoom2 = new ToolMenu("Zoom2", toolPanel2);
            BrushSize = new ToolMenu("BrushSize", toolPanel2);
            AdvancedColor = new ToolMenu("AdvancedColor", toolPanel4);
            Undo = new ToolMenu("Undo", toolPanel1);

            ToolMenu[] menuArr = {
                MainMenu,
                Contours,
                BrushType,
                //Figures,
                Selection1,
                Selection2,
                //Selection3,
                File1,
                File2,
                Zoom1,
                Zoom2,
                BrushSize,
                AdvancedColor,
                Undo
            };

            foreach (ToolMenu tm in menuArr)
                menus.Add(tm.Name, tm);

            FillTool fillTool = new FillTool();
            ColorSelectionTool colorSelectionTool = new ColorSelectionTool();
            //penWidthTC = new ToolCollection("PenWidth", "BrushMenu", false, new ToolMenu[] { BrushSize }, "Brush width menu");
            viewPaletteAction = new ViewPaletteAction();
            selectionTool = new SelectionTool();
            colorDialogAction = new ColorDialogAction();
            BrushTool brushTool = new BrushTool();
            LineTool lineTool = new LineTool();
            ZoomInTool zoomInTool = new ZoomInTool();
            SubMenuAction fileMenu = new SubMenuAction("Menu", "Menu", new ToolMenu[] { File1, File2 }, "File menu", null);
            transparentSelectionAction = new TransparentSelectionAction();

            smallPaletteControl1.SetColorNumber(10);

            Action[] arr = {
                fileMenu,
                new ToolCollection("Brushes", "PencilTool", true, new ToolMenu[] { BrushType, BrushSize }, "Brush menu", brushTool),
                new ToolCollection("Figures", "FilledEllipseTool", true, new ToolMenu[] { Contours, /*Figures, */BrushSize }, "Figures menu (flood fill also here)", lineTool),
                selectionTool, 
                new ZoomMenu(new ToolMenu[] { Zoom1, Zoom2 }, zoomInTool), 
                new UndoAction(new ToolMenu[] { Undo }),

                new RedoAction(),

                new AboutAction(),
                new NewAction(),
                new OpenAction(),
                new SaveAction(),
                new SaveAsAction(),
                new ChangeSizeAction(),
                new OptionsAction(),
                new CloseAction(),

                viewPaletteAction,

                zoomInTool, new ZoomOutAction(),
                new ZoomToFitAction(),
                new SetZoomAction(1 * BitmapZoomer.ZoomFactorUnit),
                new SetZoomAction(2 * BitmapZoomer.ZoomFactorUnit),
                new SetZoomAction(5 * BitmapZoomer.ZoomFactorUnit),

                new SetZoomAction(7 * BitmapZoomer.ZoomFactorUnit),
                new SetZoomAction(10 * BitmapZoomer.ZoomFactorUnit),
                new SetZoomAction(15 * BitmapZoomer.ZoomFactorUnit),
                new SetZoomAction(25 * BitmapZoomer.ZoomFactorUnit),
                new SetZoomAction(BitmapZoomer.ZoomFactorUnit / 2),
                new SetZoomAction(BitmapZoomer.ZoomFactorUnit / 4),

                brushTool, new PencilTool(), new AirBrushTool(), new BlurBrushTool(), new RealAirBrushTool(),
                new SemiTransparentBrushTool(), //new MotionBlurBrushTool(),
 
                //penWidthTC,
                new PenWidthAction(1),
                //new PenWidthAction(2),
                new PenWidthAction(3),
                //new PenWidthAction(4),
                new PenWidthAction(5),
                //new PenWidthAction(7),
                new PenWidthAction(9),
                new PenWidthAction(15),
                new PenWidthAction(25),

                new CopySelectionAction(), new ResizeSelectionAction(),
                new CropSelectionAction(), new CopyToClipboardAction(),
                new CutToClipboardAction(), new PasteFromClipboardAction(),
                new RotateLeftAction(),
                new RotateRightAction(),
                new FlipHorizontalAction(),
                new FlipVerticalAction(),
                transparentSelectionAction,
                new SelectAllAction(),

                //new ToolCollection("Figures", "LineTool", true), 
                lineTool, new EllipseTool(), new FilledEllipseTool(),
                new RectangleTool(), new FilledRectangleTool(),
                fillTool, colorSelectionTool, colorDialogAction
            };

            /*if (Screen.PrimaryScreen.Bounds.Width / ImageList.ImageSize.Width / 2 - 1 < 9)
            {
                if (Screen.PrimaryScreen.Bounds.Width < Screen.PrimaryScreen.Bounds.Height)
                {
                    MessageBox.Show("It is recommended to run Pocket Picture in landscape mode. In portrait mode some buttons go into submenus.");
                }
                fillTool.ParentName = "Figures";
                colorSelectionTool.ParentName = "Figures";
                penWidthTC.ParentName = "DrawTools";
            }*/

            PaletteControl.ColorsInRow = Math.Max(2, 68 / ((PaletteControl.Height - PaletteControl.SpanSize / 2) / PaletteControl.RectangleSize) + 1);
            PaletteControl.Width = PaletteControl.ColorsInRow * PaletteControl.RectangleSize + PaletteControl.SpanSize;

            string modeName = (string) Registry.GetValue(RegKey, "Mode", "BrushTool");
            string activeMainMenuItemName = (string) Registry.GetValue(RegKey, "ActiveMainMenuItem", "Contour tools");
            //MessageBox.Show("UI");
            foreach (Action t in arr)
            {
                t.CreateUI(this);
                if (t is BrushTool)
                {
                    defaultMode = (PaintTool) t;
                    if (mode == null)
                        mode = (PaintTool) t;                    
                }

                if (t.Name == modeName && t is PaintTool)
                {
                    mode = (PaintTool) t;
                }

                if (t.Name == activeMainMenuItemName)
                {
                    activeMainMenuItem = t;
                }
            }

            if (activeMainMenuItem == null || activeMainMenuItem is UndoAction)
                activeMainMenuItem = fileMenu;
            viewPaletteAction.Element.DrawDropDownArrowIfHasChildren = false;
            MainToolBar.AssignSelfToElements();
#if !PocketPC
            this.WindowState = FormWindowState.Maximized;
            this.BitmapZoomer.ShowGridOnZoomGreaterThan = 10;
#endif
            AdvancedColor.FillMenu();

            //PaletteSelectedColor = Color.FromArgb(Convert.ToInt32(Registry.GetValue(RegKey, "SelectedColor", Color.Black.ToArgb())));
            PaletteSelectedColor = Color.Black;
            PaletteControl.Invalidate();

            byte[] bytes = (byte []) Registry.GetValue(RegKey, "OtherOptions", new byte[0]);
            if (bytes.Length != 0)
            {
                Serialization sr = new Serialization();
                sr.SerializeOnlyMarkedAsSerializable = true;
                Stream s = new MemoryStream(bytes);
                try
                {
                    sr.LoadObjProperties(this, new BinaryReader(s));
                }
                catch(SerializeFormatException)
                {
                }

                s.Close();
            }
            int educationModeWasSuggested = (int) Registry.GetValue(RegKey, "educationModeWasSuggested", 0);
            if (educationModeWasSuggested == 0)
            {
                if (MessageBox.Show("Seems like you run PocketPicture 2 for the first time. To learn its user interface I recommend to turn on hint 'double click' mode - first click shows hint and second does action. Do you want to turn hint mode on?", "Turn hint mode on?", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                    educationalMode = true;
                else
                    educationalMode = false;

                Registry.SetValue(RegKey, "educationModeWasSuggested", 1);
            }

            fullScreenMode = false;

            ToolBand.Attach();

            UpdateControlCompositionFromProperties();

            Trace.Assert(mode != null, "Mode is null. Did we forgot brush tool?");
            Trace.Assert(defaultMode != null, "Mode is null. Did we forgot brush tool?");

            if (mode is FillTool || mode is ColorSelectionTool)
                mode = defaultMode;
            activeMainMenuItem.DoAction();
            mode.DoAction();

            //newTestBitmap();
            NewBitmap(BitmapZoomer.Width - 5, BitmapZoomer.Height - 5);
            Initing = false;

            //test
            /*FieldInfo[] fa = typeof(ToolDockDirection).GetFields();
            string s = "";
            foreach (FieldInfo fi in fa)
            {
                if (fi.IsLiteral)
                    s += fi.Name + "=" + fi.GetValue(null).ToString() + " ";
            }
            MessageBox.Show(s);*/
        }

        public enum LongOrShortSide { LongSide, ShortSide }

        public void UpdateControlCompositionFromProperties()
        {
#if !PocketPC
            {
                // This is a hack to force control to recompute its size.
                // It didn't required me to sell my soul to Bill Gates. No, of course not.
                IntPtr tempHandle = this.Handle;
                bool tempSHK = this.ShowFocusCues;
            }
#endif
            transparentSelectionAction.Element.IsPushed = currentColorIsTransparentColorForSelection;

            LongOrShortSide pos;

            int size, dpi;
            bool caption;

#if PocketPC
            Graphics gr = this.CreateGraphics();
            if (toolPanelDockDirection == ToolDockDirection.Bottom || toolPanelDockDirection == ToolDockDirection.Top)
            {
                size = Screen.PrimaryScreen.Bounds.Width;
                dpi = (int) gr.DpiX;
                caption = false;
            }
            else
            {
                size = Screen.PrimaryScreen.Bounds.Height;
                dpi = (int) gr.DpiY;
                caption = !hideTitleBar;
            }

            gr.Dispose();
#else
            if (toolPanelDockDirection == ToolDockDirection.Bottom || toolPanelDockDirection == ToolDockDirection.Top)
            {
                size = this.ClientSize.Width;
            }
            else
            {
                size = this.ClientSize.Height;
            }
            caption = false;
            dpi = 192;
#endif

            int surplus = 0;
            if (size * 6 / dpi >= 20)
            {
                pos = LongOrShortSide.LongSide;
                surplus = size - 20 * dpi / 6;
            }
            else
                pos = LongOrShortSide.ShortSide;

            //MessageBox.Show(ClientSize.Height.ToString());

            if (pos == LongOrShortSide.ShortSide && caption && reducedMode)
            {
                MessageBox.Show("There is no space on screen for reduced mode because of title bar. Switching to full mode");
                reducedMode = false;
            }

#if PocketPC
            Initing = true;
            if (hideTitleBar)
                this.WindowState = FormWindowState.Maximized;
            else
                this.WindowState = FormWindowState.Normal;
            Initing = false;
#endif
            lastWidth = ClientSize.Width;

            HintLabel.Visible = !hideHintLabel;

            int floatx = 100;
            int floaty = 100;
            if (floatingForm != null)
            {
                floatx = floatingForm.Location.X;
                floaty = floatingForm.Location.Y;
                ((ToolPanel) floatingForm.MainControl).CloseDropDown();
                ((ToolPanel) floatingForm.MainControl).Detach();
                floatingForm.Close();
                floatingForm.Dispose();
                floatingForm = null;
            }

            if (paletteControlDropDown)
            {
                if (panel1.Controls.Contains(PaletteControl))
                {
                    panel1.Controls.Remove(PaletteControl);
                }

                if (!paletteAsHSV)
                    viewPaletteAction.Element.DropDownControl = PaletteControl;
                else
                    viewPaletteAction.Element.DropDownControl = null;
                PaletteControl.SetPalette(paletteColorNumber);
            }
            else
            {
                if (!panel1.Controls.Contains(PaletteControl))
                {
                    panel1.Controls.Add(PaletteControl);
                    PaletteControl.Visible = true;
                    //viewPaletteAction.SetPushed(true);
                    viewPaletteAction.Element.DropDownControl = null;
                }
                PaletteControl.Dock = (DockStyle) (int) paletteDockDirection;
                PaletteControl.SetPalette(paletteColorNumber);
                PaletteControl.Refresh();
            }

            if (fullScreenMode)
            {
                ToolBand.Visible = false;
                ToolPanel tp = new ToolPanel();
                tp.ShowText = ShowTextEnum.ShowTextIfNoImage;
                tp.SpanSize = MainToolBar.SpanSize;
                tp.ImageSize = MainToolBar.ImageSize;
                tp.ImageList = ImageList;
                tp.SelectionColor = SystemColors.Window;
                tp.SelectionTextColor = SystemColors.ControlText;
                tp.ClickElement += new ClickElement(MainToolBar_ClickElement);
                ToolPanelElement tpe = new ToolPanelElement();
                tpe.ImageIndex = 0;
                tpe.ChildElements.AddRange(MainToolBar.ChildElements);
                tpe.ChildElements.Remove(viewPaletteAction.Element);
                //tpe.ChildElements.Remove(penWidthTC.Element);

                tp.ChildElements.Add(tpe);
                tp.ChildElements.Add(viewPaletteAction.Element);
                //tp.ChildElements.Add(penWidthTC.Element);
                tp.AssignSelfToElements();
                tp.LayoutMethod = Orientation.Vertical;
                Size sz = tpe.ComputeSize();
                tp.Size = new Size(sz.Width + tp.SpanSize * 2, sz.Height * 3 + tp.SpanSize * 4);
                tp.ElementLayout();
                floatingForm = new FloatingForm(tp, this);
                floatingForm.Location = new Point(floatx, floaty);
                floatingForm.Show();
            }
            else
            {
                ToolBand.Dock = (DockStyle) (int) toolPanelDockDirection;
                ToolBand.Visible = true;

                if (toolPanelDockDirection == ToolDockDirection.Bottom || toolPanelDockDirection == ToolDockDirection.Top)
                    MainToolBar.ShowAsTabs = ShowAsTabs.Left;
                else
                    MainToolBar.ShowAsTabs = ShowAsTabs.Top;

                if (reducedMode)
                {
                    MainToolBar.FixedArea = (MainToolBar.ImageSize + MainToolBar.SpanSize) * (MainToolBar.ImageSize + MainToolBar.SpanSize) * 6;
                    toolPanel1.FixedArea = (toolPanel1.ImageSize + toolPanel1.SpanSize) * (toolPanel1.ImageSize + toolPanel1.SpanSize) * 6;
                    if (pos == LongOrShortSide.LongSide)
                    {
                        toolPanel2.FixedArea = (toolPanel2.ImageSize + toolPanel2.SpanSize) * (toolPanel2.ImageSize + toolPanel2.SpanSize) * 6;
                        toolPanel4.FixedArea = (toolPanel4.ImageSize + toolPanel4.SpanSize) * (toolPanel4.ImageSize + toolPanel4.SpanSize) * 2;
                        if (caption)
                        {
                            smallPaletteControl1.FixedArea = (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize) * (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize) * (17 + surplus * 3 / (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize));
                            smallPaletteControl1.SetColorNumber(15 + surplus * 3 / (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize));
                        }
                        else
                        {
                            smallPaletteControl1.FixedArea = (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize) * (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize) * (21 + surplus * 3 / (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize));
                            smallPaletteControl1.SetColorNumber(18 + surplus * 3 / (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize));
                        }
                    }
                    else
                    {
                        toolPanel2.FixedArea = (toolPanel2.ImageSize + toolPanel2.SpanSize) * (toolPanel2.ImageSize + toolPanel2.SpanSize) * 4;
                        toolPanel4.FixedArea = (toolPanel4.ImageSize + toolPanel4.SpanSize) * (toolPanel4.ImageSize + toolPanel4.SpanSize) * 2;
                        smallPaletteControl1.FixedArea = (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize) * (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize) * 7;
                        smallPaletteControl1.SetColorNumber(6);
                    }
                }
                else
                {
                    MainToolBar.FixedArea = (MainToolBar.ImageSize + MainToolBar.SpanSize) * (MainToolBar.ImageSize + MainToolBar.SpanSize) * 6;
                    toolPanel1.FixedArea = (toolPanel1.ImageSize + toolPanel1.SpanSize) * (toolPanel1.ImageSize + toolPanel1.SpanSize) * 6;
                    toolPanel2.FixedArea = (toolPanel2.ImageSize + toolPanel2.SpanSize) * (toolPanel2.ImageSize + toolPanel2.SpanSize) * 6;
                    if (pos == LongOrShortSide.LongSide)
                    {
                        toolPanel4.FixedArea = (toolPanel4.ImageSize + toolPanel4.SpanSize) * (toolPanel4.ImageSize + toolPanel4.SpanSize) * 4;
                        if (caption)
                        {
                            smallPaletteControl1.FixedArea = (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize) * (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize) * (11.1f + surplus * 3 / (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize));
                            smallPaletteControl1.SetColorNumber(9 + surplus * 3 * 94 / (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize) / 100);
                        }
                        else
                        {
                            smallPaletteControl1.FixedArea = (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize) * (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize) * (18 + surplus * 3 / (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize));
                            smallPaletteControl1.SetColorNumber(15 + surplus * 3 * 94 / (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize) / 100);
                        }
                    }
                    else
                    {
                        toolPanel4.FixedArea = (toolPanel4.ImageSize + toolPanel4.SpanSize) * (toolPanel4.ImageSize + toolPanel4.SpanSize) * 3;
                        if (caption)
                        {
                            smallPaletteControl1.FixedArea = (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize) * (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize) * 20;
                            smallPaletteControl1.SetColorNumber(20);
                        }
                        else
                        {
                            smallPaletteControl1.FixedArea = (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize) * (smallPaletteControl1.ImageSize + smallPaletteControl1.SpanSize) * 30;
                            smallPaletteControl1.SetColorNumber(30);
                        }
                    }
                }

                BrushSize.Elements[1].Visible = (!reducedMode) || (pos == LongOrShortSide.LongSide);
                BrushSize.Elements[3].Visible = (!reducedMode) || (pos == LongOrShortSide.LongSide);
                AdvancedColor.Elements[2].Visible = !reducedMode;
                Zoom2.Elements[4].Visible = (!reducedMode) || (pos == LongOrShortSide.LongSide);
                Zoom2.Elements[5].Visible = (!reducedMode) || (pos == LongOrShortSide.LongSide);
                Selection2.Elements[1].Visible = (!reducedMode) || (pos == LongOrShortSide.LongSide);
                Selection2.Elements[5].Visible = (!reducedMode) || (pos == LongOrShortSide.LongSide);
                AdvancedColor.FillMenu();
                if (toolPanel2.ChildElements.Count > 0 && BrushSize.Elements[0] == toolPanel2.ChildElements[0])
                    BrushSize.FillMenu();
                ToolBand.LayoutPanels();
                if (activeMainMenuItem != null && reorderTabsAfterSelection)
                    MainToolBar.ShiftElementToLastLine(activeMainMenuItem.Element);
                smallPaletteControl1.ColorChanged(PaletteSelectedColor);
                //MainToolBar.Refresh();
            }


            if (paletteControlDropDown)
                viewPaletteAction.SetPushed(false);
            else
                viewPaletteAction.SetPushed(true);


            PaletteControl.SetPalette(paletteColorNumber);
            if (panel1.Controls.Contains(PaletteControl))
            {
                PaletteControl.Refresh();
            }
        }

        /*protected override void OnActivated(EventArgs e)
        {
            if (floatingForm != null)
            {
                if (!floatingForm.Visible)
                    floatingForm.TopMost = true;
                //floatingForm.ActivateMe();
            }
            base.OnActivated(e);
        }*/
        
        private void PocketPictureForm_Resize(object sender, EventArgs e)
        {
            if ((!Initing) && (lastWidth != ClientSize.Width))
                UpdateControlCompositionFromProperties();
            //MainToolBar.Height = MainToolBar.ElementLayout();
        }

        public void ShowMenus(ToolMenu[] menus)
        {
            toolPanel1.ChildElements.Clear();
            toolPanel2.ChildElements.Clear();
            //toolPanel3.ChildElements.Clear();

            foreach (ToolMenu tm in menus)
                tm.FillMenu();

            ToolBand.LayoutPanels();
        }

        void newTestBitmap()
        {
            Bitmap bmp = new Bitmap(470, 330, PixelFormat.Format32bppRgb);
            Graphics gr = Graphics.FromImage(bmp);
            gr.FillRectangle(new SolidBrush(Color.Black), 0, 0, bmp.Width, bmp.Height);
            gr.Dispose();



            // Lock the bitmap's bits.
            //Rectangle rect = new Rectangle(bmp.Width / 2, bmp.Height / 2, 5, 5);
            Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);

            MessageBox.Show("Begin");
            {
                int tc = Environment.TickCount;
                PixelFormat pxf = PixelFormat.Format32bppRgb;
                for (int i = 0; i < 150; i++)
                    unsafe
                    {
                        BitmapData bmpData =
                            bmp.LockBits(rect, ImageLockMode.ReadWrite,
                                 pxf);
                        byte* pSourceRow = (byte*) bmpData.Scan0.ToPointer();
                        pSourceRow[0] = (byte) (i % 256);
                        bmp.UnlockBits(bmpData);
                    }
                int tc1 = Environment.TickCount;
                MessageBox.Show("End " + (tc1 - tc).ToString());
            }
            /*MessageBox.Show("Begin1");
            {
                int tc = Environment.TickCount;
                PixelFormat pxf = PixelFormat.Format24bppRgb;
                for (int i = 0; i < 150; i++)
                    unsafe
                    {
                        BitmapData bmpData =
                            bmp.LockBits(rect, ImageLockMode.ReadWrite,
                                 pxf);
                        byte* pSourceRow = (byte*) bmpData.Scan0.ToPointer();
                        pSourceRow[0] = (byte) (i % 256);
                        bmp.UnlockBits(bmpData);
                    }
                int tc1 = Environment.TickCount;
                MessageBox.Show("End " + (tc1 - tc).ToString());
            }*/
            // Get the address of the first line.
            /*IntPtr ptr = bmpData.Scan0;
            HintLabel.Text = bmpData.Stride.ToString();
            //stride = bmpData.Stride;

            unsafe
            {
                byte* pSourceRow = (byte*) bmpData.Scan0.ToPointer();
                for (int y = 0; y < rect.Height; y++)
                {
                    for (int x = 0; x < rect.Width; x++)
                    {
                        if (x == y)
                            pSourceRow[y * bmpData.Stride + x * 3] = 255;
                        //rgbValues[counter + 1] = 255;
                        //rgbValues[counter + 2] = 255;
                        //counter += 3;
                    }
                }
            }

            // Unlock the bits.
            bmp.UnlockBits(bmpData);*/



            SetNew(bmp);
            fileName = "";
            hasUnsavedModifications = false;
        }

        /*public void SetDefaultAction(Action parentAction, Action childAction)
        {
            defaultMenuItems[parentAction] = childAction;
            parentAction.UpdatePicture(childAction);
        }*/

        protected override void ScaleControl(SizeF factor, BoundsSpecified specified)
        {
            //MessageBox.Show(factor.Width.ToString() + ":" + factor.Height.ToString());
            if (Screen.PrimaryScreen.Bounds.Height > 480)
            {
                ImageList.ImageSize = new Size(32, 32);
            }
            else
            {
                ImageList.ImageSize = new Size(
                    (int) (ImageList.ImageSize.Width * factor.Width),
                    (int) (ImageList.ImageSize.Height * factor.Height));
            }

            BitmapZoomer.ShowGridOnZoomGreaterThan = (int) (BitmapZoomer.ShowGridOnZoomGreaterThan * factor.Width);
            base.ScaleControl(factor, specified);
        }

        public bool CheckSaved()
        {
            if (hasUnsavedModifications)
            {
                DialogResult dr = MessageBox.Show("Your image has unsaved modifications. Do you want to save it now?",
                    "Save confirmation",
                    MessageBoxButtons.YesNoCancel, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
                if (dr == DialogResult.Yes)
                {
                    return Save();
                }
                else if (dr == DialogResult.No)
                    return true;
                else
                    return false;
            }
            else
                return true;
        }

        void SetNew(Bitmap bmp)
        {
            Mode.ClearStatus();
            if (BitmapZoomer.Bitmap != null)
                BitmapZoomer.Bitmap.Dispose();

            BitmapZoomer.Bitmap = bmp;

            if (lastModifications != null)
                lastModifications.Dispose();

            foreach (Bitmap b in undoStack)
                b.Dispose();

            undoStack.Clear();

            if (bmp != null)
                lastModifications = BitmapCloner.CloneBitmap(bmp);
        }

        private void bitmapZoomer1_BitmapMouseDown(int x, int y)
        {
            mode.MouseDown(x, y);
        }

        private void BitmapZoomer_BitmapMouseMove(int x, int y)
        {
            mode.MouseMove(x, y);
        }

        public void PushToUndo()
        {
            foreach (Bitmap b in redoStack)
                b.Dispose();

            redoStack.Clear();
            if (lastModifications != null)
            {
                if (undoStack.Count == UndoStackDepth && undoStack.Count > 0)
                {
                    undoStack[0].Dispose();
                    undoStack.RemoveAt(0);
                }

                if (UndoStackDepth > 0)
                    undoStack.Add(lastModifications);
                else
                {
                    lastModifications.Dispose();
                    lastModifications = null;
                }
            }

            try
            {
                lastModifications = BitmapCloner.CloneBitmap(BitmapZoomer.Bitmap);
            }
            catch (OutOfMemoryException)
            {
                MessageBox.Show("Memory is too low. Have to clear undo buffer - no undo will be possible. If problem persist, try to lower undo buffer size in the program settings.");
                if (lastModifications != null)
                    lastModifications.Dispose();

                foreach (Bitmap b in undoStack)
                    b.Dispose();

                undoStack.Clear();

                if (BitmapZoomer.Bitmap != null)
                    lastModifications = BitmapCloner.CloneBitmap(BitmapZoomer.Bitmap);
            }

            hasUnsavedModifications = true;
        }

        public void NewBitmap(int w, int h)
        {
            SetNew(null);
            Bitmap bitmap = new Bitmap(w, h, PixelFormat.Format32bppRgb);
            Graphics gr = Graphics.FromImage(bitmap);
            gr.FillRectangle(new SolidBrush(Color.White), 0, 0, bitmap.Width, bitmap.Height);
            gr.Dispose();
            SetNew(bitmap);
            fileName = "";
            hasUnsavedModifications = false;
        }

        public void OpenFile(string name)
        {
            fileName = name;
            hasUnsavedModifications = false;
            SetNew(null);
            Bitmap img = new Bitmap(fileName);
            Bitmap bmp = new Bitmap(img.Width, img.Height, PixelFormat.Format32bppRgb);
            Graphics gr = Graphics.FromImage(bmp);
            gr.DrawImage(img, new Rectangle(0, 0, img.Width, img.Height), new Rectangle(0, 0, img.Width, img.Height), GraphicsUnit.Pixel);
            gr.Dispose();
            img.Dispose();

            SetNew(bmp);
            //bitmapZoomer1.Refresh();
        }

        public bool SaveAs()
        {
            string filter = "Bitmap file (*.bmp)|*.bmp|GIF file (*.gif)|*.gif|JPEG file (*.jpg)|*.jpg|PNG file (*.png)|*.png";
            int filterIndex = 0;
            if (fileName != null)
            {
                if (fileName.EndsWith("gif"))
                    filterIndex = 2;
                else if (fileName.EndsWith("jpg"))
                    filterIndex = 3;
                else if (fileName.EndsWith("bmp"))
                    filterIndex = 1;
                else
                    filterIndex = 4;
            }

#if PocketPC
            if (useStandartFileDialog)
#endif
            {
                SaveFileDialog saveFileDialog1 = new SaveFileDialog();

                saveFileDialog1.InitialDirectory = "My Pictures";
                saveFileDialog1.Filter = filter;
                saveFileDialog1.FilterIndex = filterIndex;
                saveFileDialog1.FileName = fileName;

                if (saveFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    fileName = saveFileDialog1.FileName;
                    return Save();
                }
                else
                    return false;
            }
#if PocketPC
            else
            {
                CompleteFileDialog saveFileDialog1 = new CompleteFileDialog();
                saveFileDialog1.PreviewControl = new FileDialogPicturePreview();
                saveFileDialog1.SaveAsDialog = true;
                saveFileDialog1.OverwritePrompt = true;
                saveFileDialog1.Filter = filter;
                saveFileDialog1.FilterIndex = filterIndex;
                saveFileDialog1.FileName = fileName;
                if (saveFileDialog1.ShowDialog() == DialogResult.OK)
                {
                    fileName = saveFileDialog1.FileName;
                    return Save();
                }
                else
                    return false;
            }
#endif
        }

        public bool Save()
        {
            if (fileName == null || fileName == "")
            {
                return SaveAs();
            }

            ImageFormat fmt;
            if (fileName.EndsWith("gif"))
                fmt = ImageFormat.Gif;
            else if (fileName.EndsWith("jpg"))
                fmt = ImageFormat.Jpeg;
            else if (fileName.EndsWith("bmp"))
                fmt = ImageFormat.Bmp;
            else
                fmt = ImageFormat.Png;
            try
            {
                BitmapZoomer.Bitmap.Save(fileName, fmt);
            }
            catch (NotSupportedException)
            {
                MessageBox.Show("Unfortunately, this format is not supported on your version of Windows Mobile. Try *.bmp - it should work.");
                return false;
            }

            hasUnsavedModifications = false;
            return true;
        }

        public void SetActiveMainMenuItem(Action action)
        {
            if (activeMainMenuItem != null)
            {
                activeMainMenuItem.SetPushed(mode == activeMainMenuItem);
            }

            action.SetPushed(true);
            activeMainMenuItem = action;
            Registry.SetValue(RegKey, "ActiveMainMenuItem", activeMainMenuItem.Name);
            if (reorderTabsAfterSelection)
                MainToolBar.ShiftElementToLastLine(action.Element);
        }

        public void SetMode(PaintTool newMode)
        {
            if (newMode == null)
                newMode = defaultMode;
            mode.SetPushed(mode == activeMainMenuItem);
            mode.ClearStatus();
            mode.Cancel();

            newMode.SelectTool();

            if (activeMainMenuItem is SubMenuAction)
            {
                SubMenuAction sma = ((SubMenuAction) activeMainMenuItem);
                if (sma.DefaultPaintTool != null || newMode != defaultMode)
                {
                    bool ok = false;
                    foreach (ToolMenu tm in sma.Menus)
                    {
                        foreach (ToolPanelElement tpe in tm.Elements)
                        {
                            if (tpe.Tag == (object) newMode)
                            {
                                ok = true;
                                break;
                            }
                        }
                        if (ok)
                            break;
                    }

                    if (ok)
                        sma.DefaultPaintTool = newMode;
                }
            }

            if (!newMode.TemporaryTool())
                defaultMode = newMode;

            mode = newMode;
            mode.SetPushed(true);
            Registry.SetValue(RegKey, "Mode", mode.Name);
            BitmapZoomer.ForgetMouseDown();
        }

        public void DoUndo()
        {
            if (undoStack.Count == 0)
            {
                MessageBox.Show("Nothing to undo");
                return;
            }

            Mode.ClearStatus();

            if (lastModifications != null)
            {
                lastModifications.Dispose();
                lastModifications = null;
            }

            Bitmap b = undoStack[undoStack.Count - 1];
            redoStack.Add(BitmapZoomer.Bitmap);
            //BitmapZoomer.Bitmap.Dispose();
            BitmapZoomer.Bitmap = b;
            undoStack.RemoveAt(undoStack.Count - 1);
            lastModifications = BitmapCloner.CloneBitmap(BitmapZoomer.Bitmap);
        }

        public void DoRedo()
        {
            if (redoStack.Count == 0)
            {
                MessageBox.Show("Nothing to redo");
                return;
            }

            Mode.ClearStatus();

            if (lastModifications != null)
            {
                lastModifications.Dispose();
                lastModifications = null;
            }

            Bitmap b = redoStack[redoStack.Count - 1];
            undoStack.Add(BitmapZoomer.Bitmap);
            //BitmapZoomer.Bitmap.Dispose();
            BitmapZoomer.Bitmap = b;
            redoStack.RemoveAt(redoStack.Count - 1);
            lastModifications = BitmapCloner.CloneBitmap(BitmapZoomer.Bitmap);
        }

        private void PaletteControl_ColorSelected(object sender, EventArgs e)
        {
            PaletteSelectedColor = PaletteControl.SelectedColor;
        }

        private void BitmapZoomer_ZoomFactorChanged(object sender, EventArgs e)
        {
            /*if (!Initing)
                Registry.SetValue(RegKey, "ZoomFactor", BitmapZoomer.ZoomFactor);*/

            if (BitmapZoomer.SelectionRect.Width != 0 && BitmapZoomer.SelectionRect.Height != 0)
            {
                ScrollBox.Position = new Point(
                    (BitmapZoomer.SelectionRect.X - 5) * 
                    BitmapZoomer.ZoomFactor / BitmapZoomer.ZoomFactorUnit,
                    (BitmapZoomer.SelectionRect.Y - 5) * 
                    BitmapZoomer.ZoomFactor / BitmapZoomer.ZoomFactorUnit);
            }
        }

        public void ChangeSize()
        {
            SizeForm sf = new SizeForm();

            sf.WidthEdit = BitmapZoomer.Bitmap.Width;
            sf.HeightEdit = BitmapZoomer.Bitmap.Height;
            sf.ResizeCheck.Visible = true;
            if (sf.ShowDialog() == DialogResult.OK)
            {
                Registry.SetValue(RegKey, "ImageWidth", sf.WidthEdit);
                Registry.SetValue(RegKey, "ImageHeight", sf.HeightEdit);
                Bitmap newBitmap = new Bitmap(sf.WidthEdit, sf.HeightEdit, PixelFormat.Format32bppRgb);
                Graphics gr = Graphics.FromImage(newBitmap);
                gr.FillRectangle(new SolidBrush(PaletteSelectedColor), 0, 0, sf.WidthEdit + 1, sf.HeightEdit + 1);
                if (sf.ResizeCheck.Checked)
                {
                    gr.DrawImage(BitmapZoomer.Bitmap, new Rectangle(0, 0, sf.WidthEdit, sf.HeightEdit),
                        new Rectangle(0, 0, BitmapZoomer.Bitmap.Width, BitmapZoomer.Bitmap.Height), GraphicsUnit.Pixel);
                }
                else
                {
                    gr.DrawImage(BitmapZoomer.Bitmap, new Rectangle(0, 0, BitmapZoomer.Bitmap.Width, BitmapZoomer.Bitmap.Height), 
                        new Rectangle(0, 0, BitmapZoomer.Bitmap.Width, BitmapZoomer.Bitmap.Height), GraphicsUnit.Pixel);
                }
                BitmapZoomer.Bitmap.Dispose();
                gr.Dispose();

                BitmapZoomer.Bitmap = newBitmap;
                PushToUndo();
                //newBitmap(sf.WidthEdit, sf.HeightEdit);
            }
        }

        private void PocketPictureForm_Closing(object sender, CancelEventArgs e)
        {
            if (hasUnsavedModifications)
            {
                DialogResult dr = MessageBox.Show("Your image has unsaved modifications. Really quit?",
                    "Save confirmation",
                    MessageBoxButtons.OKCancel, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
                if (dr == DialogResult.Cancel)
                {
                    e.Cancel = true;
                }
            }
        }

        private bool MainToolBar_ClickElement(ToolPanelElement elem, int x, int y)
        {
            if (elem is ColorElement)
            {
                if (elem.IsPushed && paletteAsHSV)
                {
                    elem.Panel.DisplayDropDownMenuForToolBand(elem, new HSVDropDownControl(this, (ColorElement) elem), ToolBand);
                }
                else
                {
                    PaletteSelectedColor = ((ColorElement) elem).Color;
                }

                return true;
            }

            if (educationalMode && lastElement != elem && elem.Tag != null)
            {
                HintLabel lbl = new HintLabel(this, ((Action) elem.Tag).Hint + ".\r\nPress again to do this action.");
                elem.Panel.DisplayDropDownMenuForToolBand(elem, lbl, ToolBand);
                lastElement = elem;
            }
            else
            {
                lastElement = elem;
                if (elem.Tag != null)
                {
                    if (elem.Panel != MainToolBar)
                    {
                        elem.IsPushed = !elem.IsPushed;
                        elem.Refresh();
                        elem.IsPushed = !elem.IsPushed;
                        elem.Refresh();
                    }

                    bool closeAction = elem.Tag is CloseAction;
                    ((Action) elem.Tag).DoAction();
                    return ((Action) elem.Tag).CloseDropDownOnClick;

                    /*if (closeAction)
                        return false;
                    else
                        return !((Action) elem.Tag).CreateChildMenu;*/
                }
                else
                {
                    if (elem.ChildElements.Count > 0)
                        elem.Panel.DisplayDropDownMenu(elem);
                }
            }

            return false;
        }

        private void BitmapZoomer_BitmapMouseUp(int x, int y)
        {
            mode.MouseUp();
        }

        public void ShowColorDialog()
        {
            ColorDialog cd = new ColorDialog(this.paletteAsHSV);
            cd.ColorEdit = PaletteSelectedColor;
            if (cd.ShowDialog() == DialogResult.OK)
            {
                PaletteSelectedColor = cd.ColorEdit;
            }
            cd.Dispose();
        }
    }

}